
#include "FunctionList.h"


using namespace std;

FunctionElem::FunctionElem(Function* f) {
	Fct = f;
	Next = NULL;
}

FunctionElem::~FunctionElem() {
	if (Fct) {delete Fct;}
	if (Next) {delete Next;}
}

FunctionList::FunctionList() {
	Head = NULL;
	Current = NULL;
	Length = 0;
}

FunctionList::~FunctionList() {
	if (Head) delete Head;
}

void FunctionList::addFront(Function* f){
     FunctionElem* elem = new FunctionElem(f);
     elem->Next = Head;
     Head = elem;
     Length++;
}

bool FunctionList::isEmpty() {
     return (Head == NULL);
}

int FunctionList::getLength() {
     return Length;
}

void FunctionList::print(){
     for(FunctionElem* f = Head; f!=NULL; f = f->Next){
        f->Fct->print();
     }
}

Function* FunctionList::getFirstFunction() {
	Current = Head;
	if (Current) return Current->Fct;
	else return NULL;
}

Function* FunctionList::getNextFunction() {
	if (Current && Current->Next) {
       Current = Current->Next;
       return Current->Fct;
    }
	else return NULL;	
}

Function* FunctionList::pop() {
    Function* f = NULL;
    if (Head) {
       f = Head->Fct;
       FunctionElem* new_first = Head->Next;
       Head->Next = NULL;
       Head->Fct = NULL;
       delete Head;
       Length--;
       Head = new_first;
    }
    return f;
}

void FunctionList::detachAllFunctions() {
     for (FunctionElem* e = Head ; e ; e = e->Next) 
         e->Fct=NULL;
}

void FunctionList::load(string filename) {    
  const int MAX_CHARS_PER_LINE = 512;
  const int TOKENS_PER_LINE = 4;
  const char* DELIMITER = (const char*) "\t";
  
  // open the file
  std::ifstream fin;
  fin.open(filename.c_str(), std::ifstream::in);
  
  // read and drop the header of the columns
  if (!fin.eof()) {
     char buf[MAX_CHARS_PER_LINE];
     fin.getline(buf, MAX_CHARS_PER_LINE);
  }
  
  // Loop for each row in the file
  while (!fin.eof()) {
        
           // read an entire line/row into memory
           char buf[MAX_CHARS_PER_LINE];
           fin.getline(buf, MAX_CHARS_PER_LINE);
  
           // array to store memory addresses of the tokens in buf
           const char* token[TOKENS_PER_LINE] = {}; // initialize to 0

           // parse the line into blank-delimited tokens
           token[0] = strtok(buf, DELIMITER); // first token
           for (int i = 1; i < TOKENS_PER_LINE; i++) {
               token[i] = strtok(0, DELIMITER); // subsequent tokens
           }
           
           // convert the data read into function parameters
           long start_cycle = std::atol(token[0]);
           long end_cycle = std::atol(token[1]);
           if (end_cycle != 0) {
              // end_cycle will be 0 if the last line is empty
              string trace_name (token[2]);
              string fct_name (token[3]);
              // Create the corresponding function
              Function* fct = new Function(fct_name, start_cycle, end_cycle);
              addFront(fct);
           }
    }
    fin.close();
}

void FunctionList::mirror() { 
  FunctionList* list_revert = new FunctionList();
  for (Function* f = getFirstFunction(); f; f = getNextFunction()) {
     list_revert->addFront(f);
  }
  FunctionElem* temp = Head;
  Head = list_revert->Head;
  Current = NULL;	
  for (FunctionElem* e = temp ; e ; e = e->Next) e->Fct=NULL;
  delete temp;
}
     
void FunctionList::save(char* filename) { 
  ofstream myfile;
  myfile.open (filename);  
  myfile << "Start_Cycle End_Cycle Self Children Self+Children Fct_Name" << endl;  
  for(Function* f = getFirstFunction(); f!=NULL; f = getNextFunction()){
        myfile << f->StartCycle << " " << f->EndCycle << " " << f->SelfExecTime << " " << f->ChildrenExecTime << " " << f->SelfChildrenExecTime << " " << f->FunctionName << endl;
  }  
  myfile.close();
}

     
long FunctionList::nbOccurrence(string function_name) {
  long response = 0;
  for(Function* f = getFirstFunction(); f!=NULL; f = getNextFunction()){
       if (strcmp(function_name.c_str(), f->FunctionName.c_str()) == 0) response++;
  }   
  return response;  
}

void FunctionList::getOneOfEachFunction(FunctionList* fct_list) {
  for(Function* f = fct_list->getFirstFunction(); f!=NULL; f = fct_list->getNextFunction()){
       if (nbOccurrence(f->FunctionName) == 0) addFront(f);
  }   
}

void FunctionList::filterOutFunctions() {
     FunctionElem* pred = NULL;
     FunctionElem* succ = NULL;
     for (FunctionElem* e = Head ; e ;) {
         succ = e->Next;
         if (e->Fct->ToBeFilteredOut) {
            if (Head == e) {
               Head = e->Next;               
            }
            else pred->Next = e->Next;
            e->Next = NULL;
            delete e;
         }
         else pred = e;
         e = succ;
     }
}
